Add SkyKnow - rain & snow precipitation alerts#414
Conversation
Displays upcoming rain and snow events from Open-Meteo forecasts with timing, probability, and accumulation details. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces SkyKnow, a new weather application designed to provide users with timely alerts for impending rain and snow. The app integrates with the Open-Meteo API to fetch forecast data, which is then processed and presented in an easily digestible format, highlighting key details like precipitation type, timing, and severity. It aims to enhance user awareness of upcoming weather changes, ensuring they are prepared for varying conditions. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new weather app, SkyKnow, for displaying precipitation alerts. The implementation is comprehensive, featuring API integration, data parsing, animations, and various test modes. My review focuses on improving code maintainability and ensuring adherence to the repository's style guide. The main suggestions involve externalizing large data structures and base64-encoded images, simplifying some logic, and removing unused code. Additionally, please note that the required preview images, as specified in the style guide, have not been included in this pull request.
| SNOW_PARTICLES = [ | ||
| (5, 2, 0.5, 0), | ||
| (15, 22, 0.6, 2), | ||
| (28, 8, 0.4, 1), | ||
| (42, 28, 0.7, 3), | ||
| (55, 14, 0.5, 4), | ||
| (10, 18, 0.6, 5), | ||
| (35, 5, 0.4, 2), | ||
| (50, 25, 0.8, 1), | ||
| (20, 12, 0.5, 3), | ||
| (60, 20, 0.6, 0), | ||
| (8, 28, 0.7, 4), | ||
| (48, 10, 0.5, 2), | ||
| ] | ||
| RAIN_PARTICLES = [ | ||
| (3, 1, 1.5, 0), | ||
| (12, 9, 1.8, 0), | ||
| (22, 17, 1.4, 0), | ||
| (30, 5, 2.0, 0), | ||
| (38, 25, 1.6, 0), | ||
| (46, 13, 1.9, 0), | ||
| (54, 21, 1.5, 0), | ||
| (8, 29, 1.7, 0), | ||
| (18, 7, 2.0, 0), | ||
| (33, 15, 1.8, 0), | ||
| (48, 3, 1.4, 0), | ||
| (58, 23, 1.6, 0), | ||
| (26, 11, 1.9, 0), | ||
| (41, 19, 1.5, 0), | ||
| (10, 25, 1.7, 0), | ||
| (52, 8, 2.0, 0), | ||
| ] | ||
|
|
||
| # Interval options: value is hours, forecast_days is API param | ||
| INTERVAL_OPTIONS = { | ||
| "24": 1, | ||
| "48": 2, | ||
| "72": 3, | ||
| "120": 5, | ||
| "168": 7, | ||
| } | ||
|
|
||
| # ─── Pixel art icons (8x8 base64-encoded PNGs) ─── | ||
|
|
||
| ICON_SNOW_LIGHT = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGklEQVR4nGNgQAL/gYABF/iPBPAqwik5mAEA2w4T7X2e/9EAAAAASUVORK5CYII=""" | ||
|
|
||
| ICON_SNOW_MEDIUM = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJklEQVR4nGNgQAL/gYABF/iPBPAqwimJF6DrROGj243VLXhNIAQAAqw7xYlDpPsAAAAASUVORK5CYII=""" | ||
|
|
||
| ICON_SNOW_HEAVY = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAKklEQVR4nGNggIJp06b9R8YMyABdEkURLkmsJuEE/4GAEBu7AC5BkhQCAMFiUXPU/Pu7AAAAAElFTkSuQmCC""" | ||
|
|
||
| ICON_RAIN_LIGHT = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAIklEQVR4nGNgQAIpq/7/Z8AFQJIuHf//41REUAFBKwYQAACc3Bfd0qQO/gAAAABJRU5ErkJggg==""" | ||
|
|
||
| ICON_RAIN_MEDIUM = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJUlEQVR4nGNgQAIuHf//M+ACIEkYxqmIaIBiCrqRGFZRz15cAABYzx6vpJUFKQAAAABJRU5ErkJggg==""" | ||
|
|
||
| ICON_RAIN_HEAVY = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAKUlEQVR4nGNggIJp06b9R8YMyABdEkURLkmsJuEELh3//2OjiVdAkSkApxZTC1LzE2gAAAAASUVORK5CYII=""" | ||
|
|
||
| # ─── Frog sprite (13x11 pixels) for All Clear screen ─── | ||
|
|
||
| FROG_COLORS = { | ||
| "D": "#2B7A2B", # Dark green (body, head, outline) | ||
| "G": "#45A845", # Green (lighter body sides) | ||
| "Y": "#E2BB38", # Yellow (belly) | ||
| "K": "#1E5E1E", # Eyelid (heavy drooping lids) | ||
| "E": "#CCCC55", # Eye (exposed eye slit) | ||
| "P": "#111111", # Pupil dot | ||
| "T": "#3D9E3D", # Toe pads | ||
| } | ||
|
|
||
| # Frog sprite states (13 chars wide × 11 rows) | ||
| FROG_IDLE = [ | ||
| "000DDDDDDD000", | ||
| "0KDDDDDDDDDK0", | ||
| "0KKDDDDDDDKK0", | ||
| "0EPEDDDDDEPE0", | ||
| "0DDDDDDDDDDD0", | ||
| "0DDDDDDDDDDD0", | ||
| "DGGYYYYYYYGGD", | ||
| "DGGYYYYYYYGGD", | ||
| "DGGYYYYYYYGGD", | ||
| "0DDDDDDDDDDD0", | ||
| "0TT00DDD00TT0", | ||
| ] | ||
|
|
||
| FROG_BLINK = [ | ||
| "000DDDDDDD000", | ||
| "0KDDDDDDDDDK0", | ||
| "0KKDDDDDDDKK0", | ||
| "0KKDDDDDDDKK0", # Lids shut | ||
| "0DDDDDDDDDDD0", | ||
| "0DDDDDDDDDDD0", | ||
| "DGGYYYYYYYGGD", | ||
| "DGGYYYYYYYGGD", | ||
| "DGGYYYYYYYGGD", | ||
| "0DDDDDDDDDDD0", | ||
| "0TT00DDD00TT0", | ||
| ] | ||
|
|
||
| FROG_PUFF = [ | ||
| "000DDDDDDD000", | ||
| "0KDDDDDDDDDK0", | ||
| "0KKDDDDDDDKK0", | ||
| "0EPEDDDDDEPE0", | ||
| "0DDDDDDDDDDD0", | ||
| "0DDYYYYYYYDD0", # Yellow creeps up | ||
| "DGGYYYYYYYGGD", | ||
| "DGGYYYYYYYGGD", | ||
| "DGGYYYYYYYGGD", | ||
| "0DDDDDDDDDDD0", | ||
| "0TT00DDD00TT0", | ||
| ] |
There was a problem hiding this comment.
These large data structures (SNOW_PARTICLES, RAIN_PARTICLES, FROG_COLORS, FROG_IDLE, etc.) decrease the readability of the main application logic. To improve maintainability, consider moving them into a separate helper file (e.g., sky_know_data.star) and loading them as needed.
References
- To improve readability and maintainability, move large data structures into a separate file and load them into the main application logic.
apps/skyknow/sky_know.star
Outdated
| ICON_SNOW_LIGHT = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGklEQVR4nGNgQAL/gYABF/iPBPAqwik5mAEA2w4T7X2e/9EAAAAASUVORK5CYII=""" | ||
|
|
||
| ICON_SNOW_MEDIUM = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJklEQVR4nGNgQAL/gYABF/iPBPAqwimJF6DrROGj243VLXhNIAQAAqw7xYlDpPsAAAAASUVORK5CYII=""" | ||
|
|
||
| ICON_SNOW_HEAVY = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAKklEQVR4nGNggIJp06b9R8YMyABdEkURLkmsJuEE/4GAEBu7AC5BkhQCAMFiUXPU/Pu7AAAAAElFTkSuQmCC""" | ||
|
|
||
| ICON_RAIN_LIGHT = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAIklEQVR4nGNgQAIpq/7/Z8AFQJIuHf//41REUAFBKwYQAACc3Bfd0qQO/gAAAABJRU5ErkJggg==""" | ||
|
|
||
| ICON_RAIN_MEDIUM = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJUlEQVR4nGNgQAIuHf//M+ACIEkYxqmIaIBiCrqRGFZRz15cAABYzx6vpJUFKQAAAABJRU5ErkJggg==""" | ||
|
|
||
| ICON_RAIN_HEAVY = """iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAKUlEQVR4nGNggIJp06b9R8YMyABdEkURLkmsJuEELh3//2OjiVdAkSkApxZTC1LzE2gAAAAASUVORK5CYII=""" |
There was a problem hiding this comment.
Embedding images as base64 strings is strongly discouraged by the repository's style guide as it increases file size and pollutes the context. These icons should be saved as external .png or .gif files and loaded using render.Image.
References
- It is strongly recommended to not embed images as base64-encoded strings inside the Starlark file. This is because the base64 overhead results in a roughly 33% size increase and the long strings pollute the context for AI agents. Apps should load images from external files instead. (link)
apps/skyknow/sky_know.star
Outdated
| interval_hours = int(config.get("interval", "48")) | ||
| forecast_days = INTERVAL_OPTIONS.get(str(interval_hours), 2) |
There was a problem hiding this comment.
The value from config.get("interval") is retrieved, converted to an integer, and then immediately converted back to a string for the dictionary lookup. This can be made more efficient and readable by storing the string value from the configuration and reusing it.
For example:
interval_str = config.get("interval", "48")
interval_hours = int(interval_str)
forecast_days = INTERVAL_OPTIONS.get(interval_str, 2)
interval_str = config.get("interval", "48")
interval_hours = int(interval_str)
forecast_days = INTERVAL_OPTIONS.get(interval_str, 2)
| url = ( | ||
| "https://api.open-meteo.com/v1/forecast" + | ||
| "?latitude=%s&longitude=%s" % (lat, lng) + | ||
| "&hourly=snowfall,rain,precipitation_probability,weathercode" + | ||
| "&temperature_unit=fahrenheit" + | ||
| "&timezone=%s" % tz + | ||
| "&forecast_days=%d" % forecast_days | ||
| ) |
There was a problem hiding this comment.
The URL construction is complex due to multiple string concatenations and formatting operations. This can be simplified into a single, more readable formatting operation.
For example:
url = (
"https://api.open-meteo.com/v1/forecast"
"?latitude=%s&longitude=%s"
"&hourly=snowfall,rain,precipitation_probability,weathercode"
"&temperature_unit=fahrenheit"
"&timezone=%s"
"&forecast_days=%d"
) % (lat, lng, tz, forecast_days)
url = (
"https://api.open-meteo.com/v1/forecast"
"?latitude=%s&longitude=%s"
"&hourly=snowfall,rain,precipitation_probability,weathercode"
"&temperature_unit=fahrenheit"
"&timezone=%s"
"&forecast_days=%d"
) % (lat, lng, tz, forecast_days)
apps/skyknow/sky_know.star
Outdated
| def format_time_window(start_str, end_str): | ||
| start_parts = start_str.split("T") | ||
| end_parts = end_str.split("T") | ||
|
|
||
| start_date = start_parts[0] | ||
| start_hour = int(start_parts[1].split(":")[0]) | ||
| end_date = end_parts[0] | ||
| end_hour = int(end_parts[1].split(":")[0]) | ||
|
|
||
| start_day = get_day_abbr(start_date) | ||
| end_day = get_day_abbr(end_date) | ||
|
|
||
| start_fmt = "%s %s" % (start_day, format_hour(start_hour)) | ||
| end_fmt = "%s %s" % (end_day, format_hour(end_hour)) | ||
|
|
||
| return "%s-%s" % (start_fmt, end_fmt) |
- Extract 6 base64 icons to images/ as PNG files per style guide - Remove unused format_time_window function - Simplify interval config: avoid redundant int→str conversion Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Details
Test plan
🤖 Generated with Claude Code